package spring.cloud.tasks.api.service.impl;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import spring.cloud.tasks.api.database.entity.StatisticsDto;
import spring.cloud.tasks.api.database.service.StatisticsDtoService;
import spring.cloud.tasks.api.domain.*;
import spring.cloud.tasks.api.service.AlarmStatisticsService;
import spring.cloud.tasks.api.service.ZooKeeperService;
import spring.cloud.tasks.api.service.helper.DashboardServiceHelper;
import spring.cloud.tasks.api.utils.StatisticsTableKeyConstant;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


public class AlarmStatisticsServiceImpl implements AlarmStatisticsService {

    @Resource
    private ZooKeeperService zooKeeperService;

    @Resource
    private StatisticsDtoService statisticsService;

    @Override
    public String getAbnormalJobsString() throws RuntimeException {
        List<AbnormalJob> abnormalJobList = getAbnormalJobList();
        return JSON.toJSONString(DashboardServiceHelper.sortUnnormaoJobByTimeDesc(abnormalJobList));
    }

    @Override
    public String getUnableFailoverJobsString() throws RuntimeException {
        List<AbnormalJob> abnormalJobList = getUnableFailoverJobList();
        return JSON.toJSONString(abnormalJobList);
    }

    @Override
    public String getTimeout4AlarmJobsString() throws RuntimeException {
        List<Timeout4AlarmJob> timeout4AlarmJobList = getTimeout4AlarmJobList();
        return JSON.toJSONString(timeout4AlarmJobList);
    }


    @Override
    public List<AlarmJobCount> getCountOfAlarmJobs() throws RuntimeException {
        List<AlarmJobCount> alarmJobCountList = new ArrayList<>();
        alarmJobCountList.add(new AlarmJobCount(StatisticsTableKeyConstant.UNNORMAL_JOB, getAbnormalJobList().size()));
        alarmJobCountList.add(
                new AlarmJobCount(StatisticsTableKeyConstant.UNABLE_FAILOVER_JOB, getUnableFailoverJobList().size()));
        alarmJobCountList.add(
                new AlarmJobCount(StatisticsTableKeyConstant.TIMEOUT_4_ALARM_JOB, getTimeout4AlarmJobList().size()));

        return alarmJobCountList;
    }

    @Override
    public String getAbnormalContainers() throws RuntimeException {
        List<AbnormalContainer> abnormalContainerList = new ArrayList<>();
        Collection<ZooKeeperCluster> zkClusterList = zooKeeperService.getZooKeeperClusterList();
        for (ZooKeeperCluster zkCluster : zkClusterList) {
            String result = getAbnormalContainers(zkCluster.getZooKeeperClusterKey());
            List<AbnormalContainer> tempList = JSON.parseArray(result, AbnormalContainer.class);
            if (tempList != null) {
                abnormalContainerList.addAll(tempList);
            }
        }
        return JSON.toJSONString(abnormalContainerList);
    }

    @Override
    public void setAbnormalJobMonitorStatusToRead(String uuid) throws RuntimeException {
        if (StringUtils.isBlank(uuid)) {
            throw new RuntimeException("uuid不能为空");
        }
        setAlarmJobMonitorStatusToRead(uuid, StatisticsTableKeyConstant.UNNORMAL_JOB, AbnormalJob.class);
    }

    @Override
    public void setTimeout4AlarmJobMonitorStatusToRead(String uuid) throws RuntimeException {
        if (StringUtils.isBlank(uuid)) {
            throw new RuntimeException("uuid不能为空");
        }
        setAlarmJobMonitorStatusToRead(uuid, StatisticsTableKeyConstant.TIMEOUT_4_ALARM_JOB, Timeout4AlarmJob.class);
    }


    public List<AbnormalJob> getAbnormalJobList() throws RuntimeException {
        List<AbnormalJob> abnormalJobList = new ArrayList<>();
        Collection<ZooKeeperCluster> zkClusterList = zooKeeperService.getZooKeeperClusterList();
        for (ZooKeeperCluster zkCluster : zkClusterList) {
            String result = getAbnormalJobsStringByZKCluster(zkCluster.getZooKeeperClusterKey());
            List<AbnormalJob> tempList = JSON.parseArray(result, AbnormalJob.class);
            if (tempList != null) {
                abnormalJobList.addAll(tempList);
            }
        }
        return abnormalJobList;
    }

    public List<AbnormalJob> getUnableFailoverJobList() throws RuntimeException {
        List<AbnormalJob> abnormalJobList = new ArrayList<>();
        Collection<ZooKeeperCluster> zkClusterList = zooKeeperService.getZooKeeperClusterList();
        for (ZooKeeperCluster zkCluster : zkClusterList) {
            String result = getUnableFailoverJobsStringByZKCluster(zkCluster.getZooKeeperClusterKey());
            List<AbnormalJob> tempList = JSON.parseArray(result, AbnormalJob.class);
            if (tempList != null) {
                abnormalJobList.addAll(tempList);
            }

        }
        return abnormalJobList;
    }

    public List<Timeout4AlarmJob> getTimeout4AlarmJobList() throws RuntimeException {
        List<Timeout4AlarmJob> timeout4AlarmJobList = new ArrayList<>();
        Collection<ZooKeeperCluster> zkClusterList = zooKeeperService.getZooKeeperClusterList();
        for (ZooKeeperCluster zkCluster : zkClusterList) {
            String result = getTimeout4AlarmJobsStringByZKCluster(zkCluster.getZooKeeperClusterKey());
            List<Timeout4AlarmJob> tempList = JSON.parseArray(result, Timeout4AlarmJob.class);
            if (tempList != null) {
                timeout4AlarmJobList.addAll(tempList);
            }
        }
        return timeout4AlarmJobList;
    }

    private <T extends AbstractAlarmJob> void setAlarmJobMonitorStatusToRead(String uuid, String alarmJobType,
                                                                             Class<T> t) throws RuntimeException {
        Collection<ZooKeeperCluster> zkClusterList = zooKeeperService.getZooKeeperClusterList();
        for (ZooKeeperCluster zkCluster : zkClusterList) {
            StatisticsDto saturnStatistics = statisticsService.findStatisticsByNameAndZkList(alarmJobType,
                    zkCluster.getZooKeeperAddress());
            if (null == saturnStatistics) {
                continue;
            }
            String result = saturnStatistics.getResult();
            List<T> jobs = JSON.parseArray(result, t);
            if (jobs != null) {
                boolean find = false;
                for (T job : jobs) {
                    if (uuid.equals(job.getUuid())) {
                        job.setRead(true);
                        find = true;
                        break;
                    }
                }
                if (find) {
                    saturnStatistics.setResult(JSON.toJSONString(jobs));
                    statisticsService.updateByPrimaryKeySelective(saturnStatistics);
                    return;
                }
            }
        }
        throw new RuntimeException(String.format("该uuid(%s)不存在", uuid));
    }

    private ZooKeeperCluster validateAndGetZKCluster(String zkClusterKey) throws RuntimeException {
        ZooKeeperCluster zkCluster = zooKeeperService.getZooKeeperCluster(zkClusterKey);
        if (zkCluster == null) {
            throw new RuntimeException(String.format("该集群key(%s)不存在", zkClusterKey));
        }
        return zkCluster;
    }

    public String getAbnormalJobsStringByZKCluster(String zkClusterKey) throws RuntimeException {
        ZooKeeperCluster zkCluster = validateAndGetZKCluster(zkClusterKey);
        StatisticsDto saturnStatistics = statisticsService
                .findStatisticsByNameAndZkList(StatisticsTableKeyConstant.UNNORMAL_JOB, zkCluster.getZooKeeperAddress());
        return saturnStatistics != null ? saturnStatistics.getResult() : null;
    }

    @Override
    public String getUnableFailoverJobsStringByZKCluster(String zkClusterKey) throws RuntimeException {
        ZooKeeperCluster zkCluster = validateAndGetZKCluster(zkClusterKey);
        StatisticsDto saturnStatistics = statisticsService
                .findStatisticsByNameAndZkList(StatisticsTableKeyConstant.UNABLE_FAILOVER_JOB, zkCluster.getZooKeeperAddress());
        return saturnStatistics != null ? saturnStatistics.getResult() : null;
    }

    @Override
    public String getTimeout4AlarmJobsStringByZKCluster(String zkClusterKey) throws RuntimeException {
        ZooKeeperCluster zkCluster = validateAndGetZKCluster(zkClusterKey);
        StatisticsDto saturnStatistics = statisticsService
                .findStatisticsByNameAndZkList(StatisticsTableKeyConstant.TIMEOUT_4_ALARM_JOB, zkCluster.getZooKeeperAddress());
        return saturnStatistics != null ? saturnStatistics.getResult() : null;
    }


    @Override
    public String getAbnormalContainers(String zkClusterKey) throws RuntimeException {
        ZooKeeperCluster zkCluster = validateAndGetZKCluster(zkClusterKey);
        StatisticsDto saturnStatistics = statisticsService
                .findStatisticsByNameAndZkList(StatisticsTableKeyConstant.ABNORMAL_CONTAINER, zkCluster.getZooKeeperAddress());
        return saturnStatistics != null ? saturnStatistics.getResult() : null;
    }

    private NameSpaceConfiguration validateAndGetConf(String namespace) throws RuntimeException {
        NameSpaceConfiguration conf = zooKeeperService.getNameSpaceConfigurationByNameSpace(namespace);
        if (conf == null) {
            throw new RuntimeException(String.format("该域(%s)不存在", namespace));
        }
        return conf;
    }

    @Override
    public List<AbnormalJob> getAbnormalJobListByNamespace(String namespace) throws RuntimeException {
        List<AbnormalJob> abnormalJobList = new ArrayList<>();
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getAbnormalJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        abnormalJobList.addAll(getAlarmJobListFilterByNamespace(namespace, result, AbnormalJob.class));
        return abnormalJobList;
    }

    @Override
    public String getAbnormalJobsStringByNamespace(String namespace) throws RuntimeException {
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getAbnormalJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        return JSON.toJSONString(getAlarmJobListFilterByNamespace(namespace, result, AbnormalJob.class));
    }

    public List<AbnormalJob> getUnableFailoverListByNamespace(String namespace) throws RuntimeException {
        List<AbnormalJob> abnormalJobList = new ArrayList<>();
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getUnableFailoverJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        abnormalJobList.addAll(getAlarmJobListFilterByNamespace(namespace, result, AbnormalJob.class));
        return abnormalJobList;
    }

    @Override
    public String getUnableFailoverJobsStringByNamespace(String namespace) throws RuntimeException {
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getUnableFailoverJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        return JSON.toJSONString(getAlarmJobListFilterByNamespace(namespace, result, AbnormalJob.class));
    }

    public List<Timeout4AlarmJob> getTimeout4AlarmJobListByNamespace(String namespace)
            throws RuntimeException {
        List<Timeout4AlarmJob> timeout4AlarmJobs = new ArrayList<>();
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getTimeout4AlarmJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        timeout4AlarmJobs.addAll(getAlarmJobListFilterByNamespace(namespace, result, Timeout4AlarmJob.class));
        return timeout4AlarmJobs;
    }


    @Override
    public String getTimeout4AlarmJobsStringByNamespace(String namespace) throws RuntimeException {
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getTimeout4AlarmJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        return JSON.toJSONString(getAlarmJobListFilterByNamespace(namespace, result, Timeout4AlarmJob.class));
    }


    @Override
    public List<AlarmJobCount> getCountOfAlarmJobsByNamespace(String namespace) throws RuntimeException {
        List<AlarmJobCount> alarmJobCountList = new ArrayList<>();
        alarmJobCountList.add(new AlarmJobCount(StatisticsTableKeyConstant.UNNORMAL_JOB,
                getAbnormalJobListByNamespace(namespace).size()));
        alarmJobCountList.add(new AlarmJobCount(StatisticsTableKeyConstant.UNABLE_FAILOVER_JOB,
                getUnableFailoverListByNamespace(namespace).size()));
        alarmJobCountList.add(new AlarmJobCount(StatisticsTableKeyConstant.TIMEOUT_4_ALARM_JOB,
                getTimeout4AlarmJobListByNamespace(namespace).size()));

        return alarmJobCountList;
    }

    @Override
    public String getAbnormalContainersByNamespace(String namespace) throws RuntimeException {
        List<AbnormalContainer> jobsByNamespace = new ArrayList<>();
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getAbnormalContainers(conf.getZooKeeperClusterKey());
        List<AbnormalContainer> jobs = JSON.parseArray(result, AbnormalContainer.class);
        if (jobs != null) {
            for (AbnormalContainer job : jobs) {
                if (namespace.equals(job.getDomainName())) {
                    jobsByNamespace.add(job);
                }
            }
        }
        return JSON.toJSONString(jobsByNamespace);
    }

    @Override
    public AbnormalJob isAbnormalJob(String namespace, String jobName) throws RuntimeException {
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getAbnormalJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        return getAlarmJobFilterByNamespaceAndJobName(namespace, jobName, result, AbnormalJob.class);
    }

    @Override
    public AbnormalJob isUnableFailoverJob(String namespace, String jobName) throws RuntimeException {
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getUnableFailoverJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        return getAlarmJobFilterByNamespaceAndJobName(namespace, jobName, result, AbnormalJob.class);
    }

    @Override
    public Timeout4AlarmJob isTimeout4AlarmJob(String namespace, String jobName) throws RuntimeException {
        NameSpaceConfiguration conf = validateAndGetConf(namespace);
        String result = getTimeout4AlarmJobsStringByZKCluster(conf.getZooKeeperClusterKey());
        return getAlarmJobFilterByNamespaceAndJobName(namespace, jobName, result, Timeout4AlarmJob.class);
    }


    private <T extends AbstractAlarmJob> List<T> getAlarmJobListFilterByNamespace(String namespace, String result,
                                                                                  Class<T> t) {
        List<T> jobsByNamespace = new ArrayList<>();
        List<T> jobs = JSON.parseArray(result, t);
        if (jobs != null) {
            for (T job : jobs) {
                if (namespace.equals(job.getNamespace())) {
                    jobsByNamespace.add(job);
                }
            }
        }
        return jobsByNamespace;
    }

    private <T extends AbstractAlarmJob> T getAlarmJobFilterByNamespaceAndJobName(String namespace, String jobName,
                                                                                  String result, Class<T> t) {
        List<T> jobs = JSON.parseArray(result, t);
        if (jobs != null) {
            for (T job : jobs) {
                if (namespace.equals(job.getNamespace()) && jobName.equals(job.getJobName())) {
                    return job;
                }
            }
        }
        return null;
    }
}
